#ifndef SOURCETRACERAY_MATH_H
#define SOURCETRACERAY_MATH_H

typedef float vec_t;
#define DECL_ALIGN(x) __declspec(align(x))
#define ALIGN16 DECL_ALIGN(16)
#define ALIGN16_POST DECL_ALIGN(16)

class Vector {

public:

    float x, y, z;

    Vector() {
        x = y = z = 0.0f;
    }

    Vector(float X, float Y, float Z) { x = X; y = Y; z = Z; };

    inline void Init(float x_, float y_, float z_)
    {
        x = x_; y = y_; z = z_;
    }

    float operator[](int i) const { return ((float*)this)[i]; };
    float& operator[](int i) { ((float*)this)[i]; };

    inline bool operator==(const Vector& v) const { return (v.x == x) && (v.y == y) && (v.z == z); }
    inline bool operator!=(const Vector& v) const { return (v.x != x) || (v.y != y) || (v.z != z); }

    inline Vector operator-() const { return {-x, -y, -z}; }
    inline Vector operator-(const float f) const { return {x - f, y - f, z - f}; }
    inline Vector operator-(const Vector& v) const { return {x - v.x, y - v.y, z - v.z}; }

    inline Vector operator+(const float f) const { return {x + f, y + f, z + f}; }
    inline Vector operator+(const Vector& v) const { return {x + v.x, y + v.y, z + v.z}; }

    inline Vector operator*(const float f) const { return {x * f, y * f, z * f}; }
    inline Vector operator*(const Vector& v) const { return {x * v.x, y * v.y, z * v.z}; }

    inline Vector operator/(const float f) const { return {x / f, y / f, z / f}; }
    inline Vector operator/(const Vector& v) const { return {x / v.x, y / v.y, z / v.z}; }

    float LengthSqr() const { return (x * x + y * y + z * z); }
};

class ALIGN16 VectorAligned : public Vector
{
public:
inline VectorAligned() {};
inline VectorAligned(vec_t X, vec_t Y, vec_t Z)
{
Init(X, Y, Z);
}

#ifdef VECTOR_NO_SLOW_OPERATIONS

private:
    // No copy constructors allowed if we're in optimal mode
    VectorAligned(const VectorAligned& vOther);
    VectorAligned(const Vector& vOther);

#else
public:
explicit VectorAligned(const Vector& vOther)
{
    Init(vOther.x, vOther.y, vOther.z);
}

VectorAligned& operator=(const Vector& vOther)
{
    Init(vOther.x, vOther.y, vOther.z);
    return *this;
}

#endif
float w;	// this space is used anyway
} ALIGN16_POST;

#endif //SOURCETRACERAY_MATH_H
